package tests;

import java.util.ArrayList;
import java.util.Collection;

import junit.framework.Assert;
import junit.framework.TestCase;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import terms.Call;
import terms.Function;
import terms.AbstractTerm;
import terms.Variable;

/**
 * 31 mars 2012.
 * @author Pierre Reliquet, Simon Devineau.
 *         Ecole des Mines de Nantes.
 *         Major in Information and Communications Systems Engineering.
 *         CallTest.java
 */
public class CallTest extends TestCase {
    /**
     * function1 a Function used to perform test.
     */
    private Function         function1;
    /**
     * function2 a Function used to perform test.
     */
    private Function         function2;
    /**
     * functionForSetter a Function used to perform test.
     * It used for the setter.
     */
    private Function         functionForSetter;
    /**
     * call1 a Call used to perform test.
     */
    private Call             call1;
    /**
     * call2 a Call used to perform test.
     */
    private Call             call2;
    /**
     * terms a Collection of Terms used to perform tests.
     */
    private Collection<AbstractTerm> terms;
    /**
     * termsForSetter a Collection of Terms used to perform tests.
     */
    private Collection<AbstractTerm> termsForSetter;
    /**
     * var a Variable used to perform tests.
     */
    private Variable         var;
    /**
     * var1 a Variable used to perform tests.
     */
    private Variable         var1;

    @Override
    @Before
    protected void setUp() throws Exception {
        this.function1 = new Function("f1", 0);
        this.function2 = new Function("f2", 1);
        this.functionForSetter = new Function("f3", Constants.THREE);
        this.var = new Variable("var");
        this.var1 = new Variable("var1");
        this.terms = new ArrayList<AbstractTerm>();
        this.termsForSetter = new ArrayList<AbstractTerm>();
        this.terms.add(this.var);
        this.termsForSetter.add(this.var1);
        this.call1 = new Call(this.function1);
        this.call2 = new Call(this.function2, this.terms);
    }

    @Override
    @After
    protected void tearDown() throws Exception {
        this.function1 = null;
        this.function2 = null;
        this.functionForSetter = null;
        this.var = null;
        this.var1 = null;
        this.terms = null;
        this.termsForSetter = null;
        this.call1 = null;
        this.call2 = null;
    }

    /**
     * Test method for {@link terms.Call#Call(terms.AbstractTerm)}.
     */
    @Test
    public void testCall() {
        Assert.assertTrue(call1.getFunction() == function1);
    }

    /**
     * Test method for {@link terms.Call#Call(terms.AbstractTerm)}.
     */
    @Test
    public void testCallWithTerms() {
        Assert.assertTrue(call2.getFunction() == function2);
        Assert.assertTrue(call2.getArguments() == terms);
    }

    /**
     * Test method for {@link terms.Call#addTerm(terms.AbstractTerm)}.
     */
    @Test
    public void testAddTerm() {
        call1.addTerm(var1);
        Assert.assertTrue(this.call1.getArguments().equals(this.termsForSetter));
    }

    /**
     * Test method for {@link terms.Call#equals(java.lang.Object)}.
     */
    @Test
    public void testEqualsObject() {
        final boolean b1 = call2.getArguments().equals(call1.getArguments());
        final boolean b2 = call2.getRest().equals(call1.getRest());
        final boolean b3 = call2.getFunction().equals(call1.getFunction());
        Assert.assertFalse(this.call2.equals(this.call1));
        Assert.assertTrue(this.call2.equals(this.call2));
        Assert.assertFalse(b1);
        Assert.assertFalse(b2);
        Assert.assertFalse(b3);
        Assert.assertFalse(this.call2.equals(this.call1) && b1 && b2 && b3);
        Assert.assertFalse(this.call2.equals(1));
    }

    /**
     * Test method for {@link terms.Call#getArguments()}.
     */
    @Test
    public void testGetArguments() {
        Assert.assertTrue(this.call2.getArguments().equals(this.terms));
    }

    /**
     * Test method for {@link terms.Call#getFunction()}.
     */
    @Test
    public void testGetFunction() {
        Assert.assertTrue(this.call2.getFunction().equals(this.function2));
    }

    /**
     * Test method for {@link terms.Call#getLength()}.
     */
    @Test
    public void testGetLength() {
        Assert.assertTrue(this.call1.getLength() == 1);
    }

    /**
     * Test method for {@link terms.Call#getName()}.
     */
    @Test
    public void testGetName() {
        Assert.assertTrue(this.call2.getName().equals("f2"));
    }

    /**
     * Test method for {@link terms.Call#getRest()}.
     */
    @Test
    public void testGetRest() {
        Assert.assertTrue(this.call2.getRest().equals(this.terms));
    }

    /**
     * Test method for {@link terms.Call#hashCode()}.
     */
    @Test
    public void testHashCode() {
        Assert.assertEquals(this.call2.hashCode(), this.function2.hashCode()
                + this.terms.hashCode());
    }

    /**
     * Test method for {@link terms.Call#isRest()}.
     */
    @Test
    public void testIsRest() {
        Assert.assertTrue(this.call2.isRest() && !this.call1.isRest());
    }

    /**
     * Test method for {@link terms.Call#setArguments(java.util.Collection)}.
     */
    @Test
    public void testSetArguments() {
        this.call1.setArguments(this.termsForSetter);
        Assert.assertTrue(this.call1.getArguments().equals(this.termsForSetter));
    }

    /**
     * Test method for {@link terms.Call#setFunction(terms.Function)}.
     */
    @Test
    public void testSetFunction() {
        this.call1.setFunction(this.functionForSetter);
        Assert.assertTrue(this.call1.getFunction().equals(
                this.functionForSetter));
    }

    /**
     * Test method for {@link terms.Call#toString()}.
     */
    @Test
    public void testToString() {
        Assert.assertEquals(this.call2.toString(), "f2(var)");
        this.call2.addTerm(var1);
        Assert.assertEquals(this.call2.toString(), "f2(var,var1)");
    }
}
